home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Developers / URL Helper II / Source / MemoryBuffer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-21  |  7.2 KB  |  344 lines  |  [TEXT/MMCC]

  1. /***
  2.  * MemoryBuffer.c
  3.  *
  4.  *  Routines to implement a very simple memory allocation scheme.  None of the sphofistication
  5.  *  of the real mac memory manager here.  In fact, we don't even deal with "freeing" a
  6.  *  string!  We just ignore it.  This is meant as a short term way of packing some data
  7.  *  like strings together (to avoid the 255 limit and space wasted in that scheme).
  8.  *
  9.  ***/
  10. #include "MemoryBuffer.h"
  11. #include "Exceptions.h"
  12.  
  13. typedef struct {
  14.     short    checkVersion;
  15.     short    increaseSize;
  16.     short    freeBytes;
  17.     short    offsetToFreeBlock;
  18. } bufferHeader, *bufferHeaderPtr;
  19.  
  20. #define CHECK_VERSION    0xAF01
  21.  
  22. OSErr MBAddToBuffer (Handle buffer, short length);
  23.  
  24. /**
  25.  * NewMemoryBuffer
  26.  *
  27.  *  Return a pointer to a new inited area we can allocate some strings from
  28.  *
  29.  **/
  30. OSErr NewMemoryBuffer (Handle *buffer, short initalSize, short increase)
  31. {
  32.     OSErr            theErr;
  33.     bufferHeaderPtr    bufHdr;
  34.  
  35.     /**
  36.      ** Make sure incomming params are OK
  37.      **/
  38.     
  39.     theErr = paramErr;
  40.     require (initalSize > (sizeof(short)*2)
  41.                 || increase < 0, BadParameters);
  42.  
  43.     /**
  44.      ** Ok, allocate the inital size
  45.      **/
  46.  
  47.     *buffer = NewHandleClear (initalSize);
  48.     theErr = MemError ();
  49.     if (theErr == noErr && *buffer == 0)
  50.         theErr = memFullErr;
  51.     nrequire (theErr, FailedToAllocateMemory);
  52.  
  53.     /**
  54.      ** Fill in the increase size argument, and also the offset to the first free
  55.      ** block... which is just two!
  56.      **/
  57.     
  58.     bufHdr = (bufferHeaderPtr) **buffer;
  59.     bufHdr -> checkVersion = CHECK_VERSION;
  60.     bufHdr -> increaseSize = increase;
  61.     bufHdr -> freeBytes = initalSize - sizeof (bufferHeader);
  62.     bufHdr -> offsetToFreeBlock = sizeof (bufferHeader);
  63.  
  64.     /**
  65.      ** Done!
  66.      **/
  67.  
  68.     return noErr;
  69.  
  70.     /**
  71.      ** Deal with errors...
  72.      **/
  73.  
  74. FailedToAllocateMemory:        // Couldn't allocate memory for the inital buffer!
  75.  
  76. BadParameters:                // Didn't tell us something right!
  77.     *buffer = 0;
  78.     return theErr;
  79. }
  80.  
  81. /**
  82.  * DisposeMemoryBuffer
  83.  *
  84.  *  Get rid of the buffer
  85.  *
  86.  **/
  87. OSErr DisposeMemoryBuffer (Handle buffer)
  88. {
  89.     bufferHeaderPtr    bufHdr;
  90.     
  91.     require (buffer != 0
  92.         && *buffer != 0, BadParams);
  93.  
  94.     bufHdr = (bufferHeaderPtr) *buffer;
  95.     require (bufHdr->checkVersion == CHECK_VERSION, BadParamsPrime);
  96.  
  97.     DisposeHandle (buffer);
  98.     return noErr;
  99.  
  100. BadParamsPrime:
  101. BadParams:
  102.  
  103.     return paramErr;
  104. }
  105.  
  106. /**
  107.  * MBSaveString
  108.  *
  109.  *  Save a string in the current buffer.  Save the string as the string and the length
  110.  *  of the string (as a short).
  111.  *
  112.  **/
  113. OSErr MBSaveString (Handle buffer, char *string, short length, short *offset)
  114. {
  115.     OSErr                theErr;
  116.     bufferHeaderPtr        bufHdr;
  117.  
  118.     /**
  119.      ** Make sure our parameters are done right!
  120.      **/
  121.     
  122.     theErr = paramErr;
  123.     require (buffer != 0
  124.         && *buffer != 0
  125.         && string != 0
  126.         && length > 0, BadParams);
  127.  
  128.     bufHdr = (bufferHeaderPtr) *buffer;
  129.     require (bufHdr->checkVersion == CHECK_VERSION, BadParamsPrime);
  130.  
  131.     /**
  132.      ** Allocate the memory -- note that bufHdr may be invalid after the
  133.      ** return of this routine... cause the darn thing might have moved in
  134.      ** memory during allocation!
  135.      **/
  136.  
  137.     theErr = MBAllocateBuffer (buffer, length + sizeof(short), offset);
  138.     nrequire (theErr, FailedToAllocateMemory);
  139.  
  140.     /**
  141.      ** Move over the "short" index and copy the string in!
  142.      **/
  143.     
  144.     *((short *) (*buffer + *offset)) = length;
  145.     BlockMove (string, *buffer + *offset + sizeof(short), length);
  146.  
  147.     return noErr;
  148.     
  149.     /**
  150.      ** Handle errors!
  151.      **/
  152. FailedToAllocateMemory:        // Not enough memory in here! :(
  153.  
  154. BadParamsPrime:
  155. BadParams:                    // Something unhealthy came our way!
  156.  
  157.     *offset = 0;            // Make sure they can't do anything with this!
  158.     return theErr;
  159. }
  160.  
  161. /**
  162.  * MBGetPString
  163.  *
  164.  *  Get a string, and return it in a pascal format.  Truncate if too long.
  165.  *
  166.  **/
  167. OSErr MBGetPString (Handle buffer, short offset, StringPtr string)
  168. {
  169.     OSErr    theErr;
  170.     bufferHeaderPtr        bufHdr;
  171.     short    length;
  172.  
  173.     /**
  174.      ** Make sure our parameters are done right!
  175.      **/
  176.     
  177.     theErr = paramErr;
  178.     require (buffer != 0
  179.         && *buffer != 0
  180.         && offset >= sizeof(bufferHeader), BadParams);
  181.  
  182.     bufHdr = (bufferHeaderPtr) *buffer;
  183.     require (bufHdr->checkVersion == CHECK_VERSION, BadParamsPrime);
  184.  
  185.     require (bufHdr->offsetToFreeBlock > offset, BadParamsPrime2);
  186.  
  187.     /**
  188.      ** Ok -- now get out the length of the string, and figure out how
  189.      ** much we should copy...
  190.      **/
  191.  
  192.     length = *((short *) &((*buffer)[offset]));
  193.     theErr = -1;
  194.     require (length + offset < bufHdr->offsetToFreeBlock, BadOffset);
  195.     
  196.     if (length > sizeof (Str255))
  197.         length = sizeof (Str255);
  198.  
  199.     string[0] = length;
  200.     BlockMove (*buffer + offset + 2, &(string[1]), string[0]);
  201.  
  202.     return noErr;
  203.     
  204.     /**
  205.      ** Errors
  206.      **/
  207. BadOffset:                // The offset into the array didn't make any sense!
  208.  
  209. BadParamsPrime2:
  210.  
  211. BadParamsPrime:            // Got something evil in the mail!
  212. BadParams:
  213.  
  214.     string[0] = 0;
  215.  
  216.     return theErr;
  217. }
  218.  
  219. /**
  220.  * MBAllocateBuffer
  221.  *
  222.  *  Allocate some space in the buffer.  If there isn't enough room, then we had
  223.  *  better add some!
  224.  *
  225.  **/
  226. OSErr MBAllocateBuffer (Handle buffer, short length, short *offset)
  227. {
  228.     OSErr            theErr;
  229.     bufferHeaderPtr    bufHdr;
  230.  
  231.     /**
  232.      ** Make sure that our params are ok...
  233.      **/
  234.  
  235.     theErr = paramErr;
  236.     require (buffer != 0
  237.         && length > 0, BadParams);
  238.  
  239.     bufHdr = (bufferHeaderPtr) *buffer;
  240.     require (bufHdr->checkVersion == CHECK_VERSION, BadParamsPrime);
  241.  
  242.     /**
  243.      ** First, determine if there is enough memory to allocate.  If
  244.      ** not, get it.
  245.      **/
  246.  
  247.     if (bufHdr -> freeBytes < (length + sizeof (short))) {
  248.         theErr = MBAddToBuffer (buffer, length+sizeof(short));
  249.         nrequire (theErr, FailedToGetEnoughMem);
  250.         bufHdr = (bufferHeaderPtr) *buffer;
  251.     }
  252.  
  253.     /**
  254.      ** Great.  Now update the pointer stuff in the header...
  255.      **/
  256.  
  257.     *offset = bufHdr -> offsetToFreeBlock;
  258.     bufHdr -> offsetToFreeBlock += length;
  259.     bufHdr -> freeBytes -= length;
  260.  
  261.     return noErr;
  262.     
  263.     /**
  264.      ** Errors
  265.      **/
  266.  
  267. FailedToGetEnoughMem:            // Couldn't make the buffer big enough!
  268.  
  269. BadParamsPrime:
  270. BadParams:                        // We were given something evil!
  271.  
  272.     return theErr;
  273.  
  274. }
  275.  
  276. /**
  277.  * MBAddToBuffer
  278.  *
  279.  *  Ok -- length is bigger than the free space we have.  Job is to allocate
  280.  *  new free space -- do it increaseSize bytes at a time.  Make sure we have
  281.  *  atleast 1/4 of the increaseSize left over at the end of the game so we don't
  282.  *  end up doing another allocation right away...
  283.  *
  284.  **/
  285. OSErr MBAddToBuffer (Handle buffer, short length)
  286. {
  287.     OSErr            theErr;
  288.     bufferHeaderPtr    bufHdr;
  289.     short            bytesNeeded, bytesToAllocate;
  290.     short            blocksNeeded;
  291.  
  292.     /**
  293.      ** Make sure that our params are ok...
  294.      **/
  295.  
  296.     theErr = paramErr;
  297.     require (buffer != 0
  298.         && length > 0, BadParams);
  299.  
  300.     bufHdr = (bufferHeaderPtr) *buffer;
  301.     require (bufHdr->checkVersion == CHECK_VERSION, BadParamsPrime);
  302.  
  303.     /**
  304.      ** Calculate how many bytes are needed, and convert that
  305.      ** into the number of blocks we want to get.
  306.      **/
  307.     
  308.     theErr = -1;
  309.     bytesNeeded = length - bufHdr->freeBytes;
  310.     require (bytesNeeded > 0, BytesNeededNotZero);
  311.  
  312.     blocksNeeded = bytesNeeded / bufHdr->increaseSize;
  313.     if ((blocksNeeded*bufHdr->increaseSize - bytesNeeded)
  314.             < (bufHdr->increaseSize/4))
  315.         blocksNeeded++;
  316.  
  317.     bytesToAllocate = bufHdr->increaseSize * blocksNeeded;
  318.  
  319.     /**
  320.      ** Ok -- we can now do our stuff
  321.      **/
  322.  
  323.     SetHandleSize (buffer, GetHandleSize (buffer) + bytesToAllocate);
  324.     theErr = MemError ();
  325.     require (theErr, FailedToGetMoreMemory);
  326.  
  327.     return noErr;
  328.  
  329.     /**
  330.      ** Errors
  331.      **/
  332.  
  333. FailedToGetMoreMemory:            // We couldn't allocate any memory just now. :(
  334.  
  335. BytesNeededNotZero:                // Bad internal programming error!!!!
  336.  
  337. BadParamsPrime:
  338. BadParams:                        // We were given something evil!
  339.  
  340.     return theErr;
  341.  
  342.  
  343. }
  344.